-- Copyright (c) 2015,2016 Lucky Byte, Inc.
--
-- Summary : POS 009.1 特殊的功能模块
--
-- Author  : 吴小虎 <xiaohu@lucky-byte.com>
-- Since   : 2016.4.29
--
-- History
--  * 2015.5.5 : 创建此文件
--  * 2015.5.8 : 增加交易信息判断功能
--

-- 检查交易环境
if not reqt then
    logger.error('交易执行环境不完整，缺少 reqt ...')
    return nil
end
for _, k in ipairs {'uuid', 'ichnl', 'packet'} do
    if not reqt[k] then
        logger.error('交易执行环境不完整，缺少 reqt.%s ...', k)
        return nil
    end
end

require "core.p091.reqt.inner"
require "core.p091.reqt.prep"
require "core.p091.reqt.postp"


-- 获取交易信息
reqt.trinfo = lib091.trinfo(reqt.packet)


-- 验证报文有效性，对于 POS 报文，验证 MAC
--
reqt.validate = function()
    -- 平台内交易以及重组模式下的交易需要验证
    if not reqt.trinfo.inner and not reqt.ichnl.get('indirect') then
        logger.debug('此交易非平台交易，且为透传交易，无需验证 MAC...')
        return true
    end
    if reqt.trinfo.nomac then   -- 报文没有 MAC 字段
        logger.debug('此交易没有 MAC 字段，无需验证 MAC...')
        return true
    end
    if not reqt.term then
        logger.error('尚未取到终端信息，验证报文MAC失败.')
        return false
    end
    local _keys = core.json.decode(reqt.term.get('keys') or '{}')
    return lib091.verify_mac(reqt.packet, reqt.term.get('tmk'),
        _keys.mak, reqt.term.get('macalgo'))
end


-- 查询交易的商户信息，商户必须在系统内存在才允许交易
--
reqt.get_merch = function()
    local _merno = reqt.packet.get('42')
    if not _merno then
        logger.error('报文中未找到商户号[42]字段，不能获取商户信息.')
        return false
    end

    -- 平台内交易只能查询平台商户，透传渠道只能查询外联商户
    local _inside = '1 = 1'
    if reqt.trinfo.inner then
        _inside = 'inside = true'
    elseif not reqt.ichnl.get('indirect') then
        _inside = 'inside = false'
    end
    local _result = jdbc.select([[
        select * from pay_merch where merno = ? and chnl = 1 and
    ]] .. _inside, _merno)

    if _result.count == 0 then
        notify.error('系统内未查询到商户[%s]，拒绝其交易.', _merno)
        return false
    end
    local _merch = _result.get_record(0)
    if _merch.get('disabled') then
        notify.warn('商户[%s]已被禁用，不允许其交易.', _merno)
        return false
    end
    reqt.merch = _merch
    return true
end


-- 查询交易终端信息，终端必须在系统内登记
--
reqt.get_term = function()
    local _termid = reqt.packet.get('41')
    if not _termid then
        logger.error('报文中未找到终端号[41]字段，不能获取终端信息.')
        return false
    end
    local result = jdbc.select([[
        select * from pay_terms where merid = ? and termid = ?
    ]], reqt.merch.get('uuid'), _termid)
    if result.count == 0 then
        notify.error('系统内未查询到终端[%s]，拒绝其交易.', _termid)
        return false
    end
    local _term = result.get_record(0)
    if _term.get('disabled') then
        notify.error('终端[%s]已被禁用，不允许其交易.', _termid)
        return false
    end
    reqt.term = _term
    return true
end


-- 取请求报文中的主账号
reqt.get_pri_acct = function()
    local _pri_acct = reqt.packet.get('2')
    if string.trimlen(_pri_acct) > 0 then
        return _pri_acct
    end
    -- 尝试从二磁道获取
    local _track2 = reqt.packet.get('35')
    if string.trimlen(_track2) > 0 then
        local _i, _ = string.find(_track2, '[dD]')
        if _i and _i > 1 then
            local _pri_acct = string.sub(_track2, 1, _i - 1)
            if string.len(_pri_acct) < 13 then
                logger.warn('二磁道[%s]中主账号长度不足13.', _track2)
            end
            return _pri_acct
        end
        logger.warn('二磁道数据[%s]似乎被加密，不能获取主账号.', _track2)
    end
    return nil
end


-- 取请求报文中的交易金额
reqt.get_tramt = function()
    local _trans_amt = reqt.packet.get('4')
    if string.trimlen(_trans_amt) > 0 then
        return tonumber(_trans_amt) / 100
    end
    if reqt.trinfo.settl then
        logger.warn('清算交易[%s]报文中没有金额字段[4].', reqt.trinfo.name)
    end
    return nil
end


-- 通过当前渠道转发请求报文，返回响应报文
--
reqt.forward = function()
    local _indirect = reqt.ichnl.get('indirect')

    -- 如果是透传，则直接转发，不作任何处理
    if not _indirect then
        return lib091.forward({
            uuid     = reqt.uuid,
            indirect = _indirect,
            trinfo   = reqt.trinfo,
            packet   = reqt.packet,
            merch    = reqt.merch
        })
    end
    logger.error('TODO: reqt.forward indirect mode')
    return nil
end
